package com.imooc.business.core.executor.query.db;

import com.google.common.collect.Sets;
import com.imooc.business.domain.Metadata;
import com.imooc.business.domain.Rule;
import com.imooc.infra.repository.MetaDataRepository;
import com.imooc.infra.repository.RuleRepository;
import com.imooc.infra.repository.jdbc.DynamicJdbcRepository;
import com.imooc.module.collect.enums.RuleTypeEnum;
import com.imooc.module.exception.DataCenterException;
import com.imooc.module.query.request.QueryRequest;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author Tim
 * @description:
 */
@Slf4j
@Repository
public class QueryDbService extends BaseQueryDb {

    @Autowired
    private DynamicJdbcRepository dynamicJdbcRepository;

    @Autowired
    private RuleRepository repository;

    @Autowired
    private MetaDataRepository metaDataRepository;

    /**
     * 执行查询
     * @param queryRequest
     * @return
     */
    public List<Map<String, Object>> execQuery(QueryRequest queryRequest) {
        InnerModel innerModel = getInnerModel(queryRequest.getBusinessId());
        Set<String> indexNames = innerModel.getIndexNames();
        queryRequest.setIndexNames(indexNames);
        queryRequest.setZhNames(innerModel.getZhNames());
        queryRequest.setBusinessName(innerModel.getBusinessName());

        String sql = buildQuerySql(innerModel.getRuleEnName(), indexNames, queryRequest);
        Map<String, Object> params = buildParams(queryRequest);
        String dataSource = getDataSource();

        List<Map<String, Object>> resultList = dynamicJdbcRepository.queryMapList(sql, dataSource, params);
        log.info("execQuery end, sql:{}, dataSource:{}, params:{}", sql, dataSource, params);
        return resultList;
    }

    /**
     * 图表查询
     * @param queryRequest
     * @param pattern
     * @return
     */
    public List<Map<String, Object>> execChartQuery(QueryRequest queryRequest, String pattern) {
        InnerModel innerModel = getInnerModel(queryRequest.getBusinessId());
        Set<String> indexNames = innerModel.getIndexNames();
        queryRequest.setIndexNames(indexNames);
        queryRequest.setZhNames(innerModel.getZhNames());

        String sql = buildChartQuerySql(innerModel.getRuleEnName(), indexNames, queryRequest, pattern);
        Map<String, Object> params = buildParams(queryRequest);

        String dataSource = getDataSource();
        List<Map<String, Object>> resultList = dynamicJdbcRepository.queryMapList(sql, dataSource, params);
        log.info("execChartQuery start, sql:{}, dataSource:{}, params:{}, resultList:{}", sql, dataSource, params);
        return resultList;
    }

    /**
     * 根据业务id查找
     * @param businessId
     * @return
     */
    private InnerModel getInnerModel(String businessId){
        Rule rule = Optional.ofNullable(repository.getRuleByBusinessIdAndRuleType(businessId, RuleTypeEnum.COLLECT.name())).
                orElseThrow(()->new DataCenterException("当前业务id查询规则失败"));

        List<Metadata> metadatas = Optional.ofNullable(metaDataRepository.listByRuleId(rule.getId())).
                orElseThrow(()->new DataCenterException("当前业务id查询元数据失败"));;

        List<String> indexNameList = metadatas.stream().sorted(Comparator.comparing(Metadata::getRank)).map(Metadata::getEnName).collect(Collectors.toList());
        List<String> zhNameList = metadatas.stream().sorted(Comparator.comparing(Metadata::getRank)).map(Metadata::getCnName).collect(Collectors.toList());
        LinkedHashSet<String> indexNames = Sets.newLinkedHashSet(indexNameList);
        LinkedHashSet<String> zhNames = Sets.newLinkedHashSet(zhNameList);

        InnerModel innerModel = new InnerModel();
        innerModel.setIndexNames(indexNames);
        innerModel.setZhNames(zhNames);
        innerModel.setRuleEnName(rule.getEnName());
        innerModel.setBusinessName(rule.getBusinessName());

        return innerModel;
    }

    /**
     * 内部类做一些数据变换
     */
    @Data
    private static class InnerModel{
        //指标英文名称
        private LinkedHashSet<String> indexNames;
        //中文名称
        private LinkedHashSet<String> zhNames;
        private String ruleEnName;
        private String businessName;
    }
}
